import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

public class LookingAnalysisPage {
    private JPanel pagePanel;
    private JMenuBar menuBar;
    
    // 文件选择器
    private JFileChooser fileChooser;
    
    // 文本显示区域
    private JTextArea grammarTextArea;        // 文法输入区域
    private JTable firstSetTable;             // First集显示表格
    private JTable followSetTable;            // Follow集显示表格
    private JTable predictTableDisplay;       // 预测分析表显示表格
    private JTextArea inputWordTextArea;      // 输入单词串区域
    private JTextArea analysisProcessTextArea; // 分析过程显示区域
    
    // 按钮
    private JButton openFileButton;
    private JButton confirmGrammarButton;
    private JButton saveFileButton;
    private JButton constructPredictTableButton;
    private JButton computeFirstSetButton;
    private JButton computeFollowSetButton;
    private JButton oneKeyDisplayButton;
    private JButton stepDisplayButton;
    
    // 文法相关数据结构
    private List<GrammarRule> grammarRules;    // 文法产生式
    private Map<String, Set<String>> firstSets;   // First集
    private Map<String, Set<String>> followSets;  // Follow集
    private Map<String, Map<String, String>> predictTable; // 预测分析表
    private Set<String> nonTerminals;          // 非终结符
    private Set<String> terminals;             // 终结符
    private List<String> orderedNonTerminals;  // 按输入顺序排列的非终结符
    private List<String> grammarLines;         // 保存原始文法行

    public LookingAnalysisPage() {
        pagePanel = new JPanel();
        pagePanel.setLayout(null);
        pagePanel.setBounds(0, 0, 1280, 720);
        
        // 初始化数据结构
        grammarRules = new ArrayList<>();
        firstSets = new HashMap<>();
        followSets = new HashMap<>();
        predictTable = new HashMap<>();
        nonTerminals = new HashSet<>();
        terminals = new HashSet<>();
        orderedNonTerminals = new ArrayList<>();
        grammarLines = new ArrayList<>();
        
        // 初始化文件选择器
        fileChooser = new JFileChooser();
        
        // 创建菜单栏
        createMenuBar();
        
        // 创建UI组件
        createUIComponents();
    }
    
    private void createMenuBar() {
        menuBar = new JMenuBar();
        Font menuFont = new Font("Microsoft YaHei", Font.PLAIN, 16);
        menuBar.setFont(menuFont);
        
        // 文件菜单
        JMenu fileMenu = new JMenu("文件");
        fileMenu.setFont(menuFont);
        menuBar.add(fileMenu);
        
        JMenuItem openMenuItem = new JMenuItem("打开");
        openMenuItem.setFont(menuFont);
        openMenuItem.addActionListener(e -> openGrammarFile());
        fileMenu.add(openMenuItem);
        
        JMenuItem saveMenuItem = new JMenuItem("保存");
        saveMenuItem.setFont(menuFont);
        saveMenuItem.addActionListener(e -> saveResult());
        fileMenu.add(saveMenuItem);
        
        // 编辑菜单
        JMenu editMenu = new JMenu("编辑");
        editMenu.setFont(menuFont);
        menuBar.add(editMenu);
        
        JMenuItem cutMenuItem = new JMenuItem("剪切");
        cutMenuItem.setFont(menuFont);
        cutMenuItem.addActionListener(e -> {
            JTextArea focusedTextArea = getFocusedTextArea();
            if (focusedTextArea != null) focusedTextArea.cut();
        });
        editMenu.add(cutMenuItem);
        
        JMenuItem copyMenuItem = new JMenuItem("复制");
        copyMenuItem.setFont(menuFont);
        copyMenuItem.addActionListener(e -> {
            JTextArea focusedTextArea = getFocusedTextArea();
            if (focusedTextArea != null) focusedTextArea.copy();
        });
        editMenu.add(copyMenuItem);
        
        JMenuItem pasteMenuItem = new JMenuItem("粘贴");
        pasteMenuItem.setFont(menuFont);
        pasteMenuItem.addActionListener(e -> {
            JTextArea focusedTextArea = getFocusedTextArea();
            if (focusedTextArea != null) focusedTextArea.paste();
        });
        editMenu.add(pasteMenuItem);
    }
    
    private JTextArea getFocusedTextArea() {
        Component[] components = pagePanel.getComponents();
        for (Component comp : components) {
            if (comp instanceof JTextArea && comp.hasFocus()) {
                return (JTextArea) comp;
            }
        }
        return null;
    }
    
    private void createUIComponents() {
        // 左侧面板 - 文法输入和控制按钮
        JPanel leftPanel = new JPanel();
        leftPanel.setLayout(null);
        leftPanel.setBounds(20, 20, 350, 620);
        leftPanel.setBorder(new LineBorder(Color.BLUE, 2));
        pagePanel.add(leftPanel);
        
        JLabel grammarLabel = new JLabel("输入文法（每行一个产生式）:");
        grammarLabel.setBounds(10, 10, 250, 25);
        leftPanel.add(grammarLabel);
        
        grammarTextArea = new JTextArea();
        grammarTextArea.setBorder(new LineBorder(Color.GRAY, 1));
        JScrollPane grammarScrollPane = new JScrollPane(grammarTextArea);
        grammarScrollPane.setBounds(10, 40, 330, 200);
        leftPanel.add(grammarScrollPane);
        
        // 控制按钮面板
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridLayout(4, 2, 5, 5));
        buttonPanel.setBounds(10, 250, 330, 160);
        leftPanel.add(buttonPanel);
        
        openFileButton = new JButton("打开文件");
        openFileButton.addActionListener(e -> openGrammarFile());
        buttonPanel.add(openFileButton);
        
        confirmGrammarButton = new JButton("确认文法");
        confirmGrammarButton.addActionListener(e -> parseGrammar());
        buttonPanel.add(confirmGrammarButton);
        
        saveFileButton = new JButton("保存文件");
        saveFileButton.addActionListener(e -> saveResult());
        buttonPanel.add(saveFileButton);
        
        constructPredictTableButton = new JButton("构造预测分析表");
        constructPredictTableButton.addActionListener(e -> constructPredictTable());
        buttonPanel.add(constructPredictTableButton);
        
        computeFirstSetButton = new JButton("求First集");
        computeFirstSetButton.addActionListener(e -> computeFirstSet());
        buttonPanel.add(computeFirstSetButton);
        
        computeFollowSetButton = new JButton("求Follow集");
        computeFollowSetButton.addActionListener(e -> computeFollowSet());
        buttonPanel.add(computeFollowSetButton);
        
        oneKeyDisplayButton = new JButton("一键显示");
        oneKeyDisplayButton.addActionListener(e -> oneKeyDisplay());
        buttonPanel.add(oneKeyDisplayButton);
        
        stepDisplayButton = new JButton("分布显示");
        stepDisplayButton.addActionListener(e -> stepDisplay());
        buttonPanel.add(stepDisplayButton);
        
        // 输入单词串
        JLabel inputWordLabel = new JLabel("输入单词串:");
        inputWordLabel.setBounds(10, 420, 150, 25);
        leftPanel.add(inputWordLabel);
        
        inputWordTextArea = new JTextArea();
        inputWordTextArea.setBorder(new LineBorder(Color.GRAY, 1));
        JScrollPane inputWordScrollPane = new JScrollPane(inputWordTextArea);
        inputWordScrollPane.setBounds(10, 450, 330, 60);
        leftPanel.add(inputWordScrollPane);
        
        JButton analyzeButton = new JButton("开始分析");
        analyzeButton.setBounds(10, 520, 100, 30);
        analyzeButton.addActionListener(e -> performAnalysis());
        leftPanel.add(analyzeButton);
        
        // 中间面板 - First集和Follow集显示
        JPanel middlePanel = new JPanel();
        middlePanel.setLayout(null);
        middlePanel.setBounds(390, 20, 400, 620);
        middlePanel.setBorder(new LineBorder(Color.GREEN, 2));
        pagePanel.add(middlePanel);
        
        JLabel firstSetLabel = new JLabel("First集:");
        firstSetLabel.setBounds(10, 10, 100, 25);
        middlePanel.add(firstSetLabel);
        
        // First集表格
        firstSetTable = new JTable();
        firstSetTable.setFillsViewportHeight(true);
        firstSetTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        JScrollPane firstSetScrollPane = new JScrollPane(firstSetTable);
        firstSetScrollPane.setBounds(10, 40, 380, 250);
        middlePanel.add(firstSetScrollPane);
        
        JLabel followSetLabel = new JLabel("Follow集:");
        followSetLabel.setBounds(10, 300, 100, 25);
        middlePanel.add(followSetLabel);
        
        // Follow集表格
        followSetTable = new JTable();
        followSetTable.setFillsViewportHeight(true);
        followSetTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        JScrollPane followSetScrollPane = new JScrollPane(followSetTable);
        followSetScrollPane.setBounds(10, 330, 380, 250);
        middlePanel.add(followSetScrollPane);
        
        // 右侧面板 - 预测分析表和分析过程
        JPanel rightPanel = new JPanel();
        rightPanel.setLayout(null);
        rightPanel.setBounds(810, 20, 450, 620);
        rightPanel.setBorder(new LineBorder(Color.ORANGE, 2));
        pagePanel.add(rightPanel);
        
        JLabel predictTableLabel = new JLabel("预测分析表:");
        predictTableLabel.setBounds(10, 10, 150, 25);
        rightPanel.add(predictTableLabel);
        
        // 预测分析表表格
        predictTableDisplay = new JTable();
        predictTableDisplay.setFillsViewportHeight(true);
        predictTableDisplay.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JScrollPane predictTableScrollPane = new JScrollPane(predictTableDisplay);
        predictTableScrollPane.setBounds(10, 40, 430, 250);
        rightPanel.add(predictTableScrollPane);
        
        JLabel analysisProcessLabel = new JLabel("分析过程:");
        analysisProcessLabel.setBounds(10, 300, 150, 25);
        rightPanel.add(analysisProcessLabel);
        
        analysisProcessTextArea = new JTextArea();
        analysisProcessTextArea.setEditable(false);
        analysisProcessTextArea.setBorder(new LineBorder(Color.GRAY, 1));
        JScrollPane analysisProcessScrollPane = new JScrollPane(analysisProcessTextArea);
        analysisProcessScrollPane.setBounds(10, 330, 430, 250);
        rightPanel.add(analysisProcessScrollPane);
    }
    
    // 打开文法文件
    private void openGrammarFile() {
        int result = fileChooser.showOpenDialog(pagePanel);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                StringBuilder content = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    content.append(line).append("\n");
                }
                grammarTextArea.setText(content.toString());
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(pagePanel, "文件读取错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    
    // 解析文法
    private void parseGrammar() {
        String grammarText = grammarTextArea.getText();
        if (grammarText.trim().isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请输入文法！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        grammarRules.clear();
        nonTerminals.clear();
        terminals.clear();
        orderedNonTerminals.clear();
        grammarLines.clear();
        
        String[] lines = grammarText.split("\n");
        Set<String> addedNonTerminals = new LinkedHashSet<>(); // 保持插入顺序
        
        for (String line : lines) {
            line = line.trim();
            if (line.isEmpty()) continue;
            
            grammarLines.add(line); // 保存原始行
            
            // 处理 "|" 分隔的多个产生式
            if (line.contains("->")) {
                String[] parts = line.split("->");
                if (parts.length == 2) {
                    String left = parts[0].trim();
                    String right = parts[1].trim();
                    
                    // 添加非终结符并保持顺序
                    if (!addedNonTerminals.contains(left)) {
                        addedNonTerminals.add(left);
                        orderedNonTerminals.add(left);
                    }
                    nonTerminals.add(left);
                    
                    // 处理 "|" 分隔的多个右部
                    String[] alternatives = right.split("\\|");
                    for (String alternative : alternatives) {
                        alternative = alternative.trim();
                        grammarRules.add(new GrammarRule(left, alternative));
                        
                        // 收集终结符和非终结符
                        if (!alternative.equals("ε") && !alternative.equals("$") && !alternative.isEmpty()) {
                            // 简单按字符分割（适用于示例格式）
                            char[] chars = alternative.toCharArray();
                            for (char c : chars) {
                                String symbol = String.valueOf(c);
                                if (Character.isUpperCase(c)) {
                                    if (!addedNonTerminals.contains(symbol)) {
                                        // 仅当该大写字母在左侧出现过才添加到orderedNonTerminals
                                    }
                                    nonTerminals.add(symbol);
                                } else {
                                    terminals.add(symbol);
                                }
                            }
                        } else if (alternative.equals("$") || alternative.equals("ε")) {
                            // $ 和 ε 都代表空字符
                            terminals.add("$");
                        }
                    }
                }
            }
        }
        
        // 确保包含必要的终结符
        if (terminals.isEmpty()) {
            // 如果没有识别到终结符，使用默认的
            terminals.add("+");
            terminals.add("$");
            terminals.add("*");
            terminals.add("(");
            terminals.add(")");
            terminals.add("i");
        } else {
            terminals.add("$"); // 确保包含结束符
        }
        
        JOptionPane.showMessageDialog(pagePanel, "文法解析完成！共解析 " + grammarLines.size() + " 行文法", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 计算First集
    private void computeFirstSet() {
        if (grammarRules.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请先确认文法！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        firstSets.clear();
        
        // 初始化First集
        for (String nonTerminal : nonTerminals) {
            firstSets.put(nonTerminal, new HashSet<>());
        }
        for (String terminal : terminals) {
            if (!terminal.equals("$")) { // $ 代表空字符，不单独作为终结符处理
                firstSets.put(terminal, new HashSet<>(Arrays.asList(terminal)));
            }
        }
        // $ 代表空字符 ε
        firstSets.put("$", new HashSet<>(Arrays.asList("$")));
        
        boolean changed = true;
        while (changed) {
            changed = false;
            
            for (GrammarRule rule : grammarRules) {
                String left = rule.left;
                String right = rule.right;
                
                Set<String> firstSet = firstSets.get(left);
                int oldSize = firstSet.size();
                
                // 处理右部
                if (right.equals("ε") || right.equals("$") || right.isEmpty()) {
                    // 空产生式
                    firstSet.add("$");
                } else if (!right.isEmpty()) {
                    // 计算右部符号串的First集
                    boolean canDeriveEpsilon = true;
                    char[] symbols = right.toCharArray();
                    
                    for (char c : symbols) {
                        String symbol = String.valueOf(c);
                        Set<String> symbolFirstSet = firstSets.get(symbol);
                        if (symbolFirstSet != null) {
                            // 添加除$外的所有符号
                            firstSet.addAll(symbolFirstSet.stream()
                                    .filter(s -> !s.equals("$"))
                                    .collect(Collectors.toSet()));
                            
                            // 如果当前符号不能推导出$，则后续符号不需要考虑
                            if (!symbolFirstSet.contains("$")) {
                                canDeriveEpsilon = false;
                                break;
                            }
                        } else {
                            // 如果找不到符号的First集
                            canDeriveEpsilon = false;
                            break;
                        }
                    }
                    
                    // 如果所有符号都能推导出$，则整个右部能推导出$
                    if (canDeriveEpsilon) {
                        firstSet.add("$");
                    }
                }
                
                if (firstSet.size() > oldSize) {
                    changed = true;
                }
            }
        }
        
        // 显示First集
        displayFirstSet();
        JOptionPane.showMessageDialog(pagePanel, "First集计算完成！", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 显示First集
    private void displayFirstSet() {
        // 定义固定的终结符列
        String[] fixedTerminals = {"+", "$", "*", "(", ")", "i"};
        
        // 准备表格列名
        String[] columnNames = new String[fixedTerminals.length + 1];
        columnNames[0] = "First集";
        System.arraycopy(fixedTerminals, 0, columnNames, 1, fixedTerminals.length);
        
        // 使用orderedNonTerminals保持输入顺序
        Object[][] data = new Object[orderedNonTerminals.size()][columnNames.length];
        
        for (int i = 0; i < orderedNonTerminals.size(); i++) {
            String nonTerminal = orderedNonTerminals.get(i);
            data[i][0] = nonTerminal;
            
            Set<String> firstSet = firstSets.get(nonTerminal);
            if (firstSet != null) {
                for (int j = 0; j < fixedTerminals.length; j++) {
                    String terminal = fixedTerminals[j];
                    data[i][j + 1] = firstSet.contains(terminal) ? "1" : "空";
                }
            } else {
                for (int j = 0; j < fixedTerminals.length; j++) {
                    data[i][j + 1] = "空";
                }
            }
        }
        
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        firstSetTable.setModel(model);
    }
    
    // 计算Follow集
    private void computeFollowSet() {
        if (firstSets.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请先计算First集！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        followSets.clear();
        
        // 初始化Follow集
        for (String nonTerminal : nonTerminals) {
            followSets.put(nonTerminal, new HashSet<>());
        }
        
        // 开始符号的Follow集包含结束符
        if (!grammarRules.isEmpty() && !orderedNonTerminals.isEmpty()) {
            String startSymbol = orderedNonTerminals.get(0); // 第一个输入的非终结符作为开始符号
            followSets.get(startSymbol).add("$");
        }
        
        boolean changed = true;
        while (changed) {
            changed = false;
            
            for (GrammarRule rule : grammarRules) {
                String right = rule.right;
                
                if (!right.equals("ε") && !right.equals("$") && !right.isEmpty()) {
                    char[] rightSymbols = right.toCharArray();
                    
                    // 遍历右部的每个符号
                    for (int i = 0; i < rightSymbols.length; i++) {
                        String symbol = String.valueOf(rightSymbols[i]);
                        
                        // 只处理非终结符
                        if (nonTerminals.contains(symbol)) {
                            Set<String> followSet = followSets.get(symbol);
                            int oldSize = followSet.size();
                            
                            if (i == rightSymbols.length - 1) {
                                // 如果是右部最后一个符号，添加左部的Follow集
                                Set<String> leftFollowSet = followSets.get(rule.left);
                                if (leftFollowSet != null) {
                                    followSet.addAll(leftFollowSet);
                                }
                            } else {
                                // 不是最后一个符号
                                // 计算后面符号串的First集
                                boolean canDeriveEpsilon = true;
                                
                                // 处理后续每个符号
                                for (int j = i + 1; j < rightSymbols.length; j++) {
                                    String nextSymbol = String.valueOf(rightSymbols[j]);
                                    Set<String> nextFirstSet = firstSets.get(nextSymbol);
                                    
                                    if (nextFirstSet != null) {
                                        // 添加除$外的所有符号
                                        followSet.addAll(nextFirstSet.stream()
                                                .filter(s -> !s.equals("$"))
                                                .collect(Collectors.toSet()));
                                        
                                        // 如果当前符号不能推导出$，则后续符号不需要考虑
                                        if (!nextFirstSet.contains("$")) {
                                            canDeriveEpsilon = false;
                                            break;
                                        }
                                    } else {
                                        canDeriveEpsilon = false;
                                        break;
                                    }
                                }
                                
                                // 如果后续所有符号都能推导出$，则添加左部的Follow集
                                if (canDeriveEpsilon) {
                                    Set<String> leftFollowSet = followSets.get(rule.left);
                                    if (leftFollowSet != null) {
                                        followSet.addAll(leftFollowSet);
                                    }
                                }
                            }
                            
                            if (followSet.size() > oldSize) {
                                changed = true;
                            }
                        }
                    }
                }
            }
        }
        
        // 显示Follow集
        displayFollowSet();
        JOptionPane.showMessageDialog(pagePanel, "Follow集计算完成！", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 显示Follow集
    private void displayFollowSet() {
        // 定义固定的终结符列（与First集保持一致）
        String[] fixedTerminals = {"+", "$", "*", "(", ")", "i"};
        
        // 准备表格列名
        String[] columnNames = new String[fixedTerminals.length + 1];
        columnNames[0] = "Follow集";
        System.arraycopy(fixedTerminals, 0, columnNames, 1, fixedTerminals.length);
        
        // 使用orderedNonTerminals保持输入顺序
        Object[][] data = new Object[orderedNonTerminals.size()][columnNames.length];
        
        for (int i = 0; i < orderedNonTerminals.size(); i++) {
            String nonTerminal = orderedNonTerminals.get(i);
            data[i][0] = nonTerminal;
            
            Set<String> followSet = followSets.get(nonTerminal);
            if (followSet != null) {
                for (int j = 0; j < fixedTerminals.length; j++) {
                    String terminal = fixedTerminals[j];
                    data[i][j + 1] = followSet.contains(terminal) ? "1" : "空";
                }
            } else {
                for (int j = 0; j < fixedTerminals.length; j++) {
                    data[i][j + 1] = "空";
                }
            }
        }
        
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        followSetTable.setModel(model);
    }
    
    // 构造预测分析表
    private void constructPredictTable() {
        if (followSets.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请先计算Follow集！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        predictTable.clear();
        
        // 初始化预测分析表
        for (String nonTerminal : nonTerminals) {
            predictTable.put(nonTerminal, new HashMap<>());
        }
        
        for (GrammarRule rule : grammarRules) {
            String right = rule.right;
            
            Set<String> firstSet;
            
            if (right.equals("ε") || right.equals("$") || right.isEmpty()) {
                // 空产生式
                firstSet = new HashSet<>();
                firstSet.add("$");
            } else {
                // 计算右部的First集
                firstSet = calculateFirstSetForSequence(right);
            }
            
            Map<String, String> row = predictTable.get(rule.left);
            
            // 对于First集中的每个终结符（除了$）
            for (String terminal : firstSet) {
                if (!terminal.equals("$")) {
                    row.put(terminal, rule.left + " -> " + rule.right);
                }
            }
            
            // 如果First集包含$，将Follow集中的每个终结符加入预测表
            if (firstSet.contains("$")) {
                Set<String> followSet = followSets.get(rule.left);
                if (followSet != null) {
                    for (String terminal : followSet) {
                        row.put(terminal, rule.left + " -> " + rule.right);
                    }
                }
            }
        }
        
        // 显示预测分析表
        displayPredictTable();
        JOptionPane.showMessageDialog(pagePanel, "预测分析表构造完成！", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 计算符号序列的First集
    private Set<String> calculateFirstSetForSequence(String sequence) {
        Set<String> result = new HashSet<>();
        
        if (sequence.equals("ε") || sequence.equals("$") || sequence.isEmpty()) {
            result.add("$");
            return result;
        }
        
        boolean canDeriveEpsilon = true;
        char[] symbols = sequence.toCharArray();
        
        // 处理序列中的每个符号
        for (char c : symbols) {
            String symbol = String.valueOf(c);
            Set<String> symbolFirstSet = firstSets.get(symbol);
            if (symbolFirstSet != null) {
                // 添加除$外的所有符号
                result.addAll(symbolFirstSet.stream()
                        .filter(s -> !s.equals("$"))
                        .collect(Collectors.toSet()));
                
                // 如果当前符号不能推导出$，则后续符号不需要考虑
                if (!symbolFirstSet.contains("$")) {
                    canDeriveEpsilon = false;
                    break;
                }
            } else {
                canDeriveEpsilon = false;
                break;
            }
        }
        
        // 如果所有符号都能推导出$，则整个序列能推导出$
        if (canDeriveEpsilon) {
            result.add("$");
        }
        
        return result;
    }
    
    // 显示预测分析表
    private void displayPredictTable() {
        // 使用orderedNonTerminals保持输入顺序
        List<String> sortedTerminals = new ArrayList<>(terminals);
        Collections.sort(sortedTerminals);
        
        // 创建列名（非终结符 + 所有终结符）
        String[] columnNames = new String[sortedTerminals.size() + 1];
        columnNames[0] = "非终结符\\终结符";
        for (int i = 0; i < sortedTerminals.size(); i++) {
            columnNames[i + 1] = sortedTerminals.get(i);
        }
        
        // 创建表格数据
        Object[][] data = new Object[orderedNonTerminals.size()][sortedTerminals.size() + 1];
        
        for (int i = 0; i < orderedNonTerminals.size(); i++) {
            String nonTerminal = orderedNonTerminals.get(i);
            data[i][0] = nonTerminal;
            
            Map<String, String> row = predictTable.get(nonTerminal);
            if (row != null) {
                for (int j = 0; j < sortedTerminals.size(); j++) {
                    String terminal = sortedTerminals.get(j);
                    String entry = row.get(terminal);
                    data[i][j + 1] = (entry != null) ? entry : "";
                }
            } else {
                for (int j = 0; j < sortedTerminals.size(); j++) {
                    data[i][j + 1] = "";
                }
            }
        }
        
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        predictTableDisplay.setModel(model);
        
        // 调整列宽
        predictTableDisplay.getColumnModel().getColumn(0).setPreferredWidth(100);
        for (int i = 1; i < columnNames.length; i++) {
            predictTableDisplay.getColumnModel().getColumn(i).setPreferredWidth(80);
        }
    }
    
    // 一键显示所有结果
    private void oneKeyDisplay() {
        if (grammarRules.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请先确认文法！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        computeFirstSet();
        computeFollowSet();
        constructPredictTable();
        
        JOptionPane.showMessageDialog(pagePanel, "所有计算完成并已显示！", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 分布显示 - 逐行显示分析结果
    private void stepDisplay() {
        if (grammarLines.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请先确认文法！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        // 清空之前的结果
        firstSets.clear();
        followSets.clear();
        predictTable.clear();
        
        // 重新初始化
        for (String nonTerminal : nonTerminals) {
            firstSets.put(nonTerminal, new HashSet<>());
        }
        for (String terminal : terminals) {
            if (!terminal.equals("$")) {
                firstSets.put(terminal, new HashSet<>(Arrays.asList(terminal)));
            }
        }
        firstSets.put("$", new HashSet<>(Arrays.asList("$")));
        
        for (String nonTerminal : nonTerminals) {
            followSets.put(nonTerminal, new HashSet<>());
        }
        
        for (String nonTerminal : nonTerminals) {
            predictTable.put(nonTerminal, new HashMap<>());
        }
        
        // 开始符号的Follow集包含结束符
        if (!orderedNonTerminals.isEmpty()) {
            String startSymbol = orderedNonTerminals.get(0);
            followSets.get(startSymbol).add("$");
        }
        
        // 显示提示信息
        analysisProcessTextArea.setText("开始分布显示分析过程...\n");
        
        // 逐行处理文法
        for (int i = 0; i < grammarLines.size(); i++) {
            String line = grammarLines.get(i);
            analysisProcessTextArea.append("处理第 " + (i+1) + " 行文法: " + line + "\n");
            
            // 查找与该行相关的产生式
            List<GrammarRule> relatedRules = new ArrayList<>();
            if (line.contains("->")) {
                String[] parts = line.split("->");
                if (parts.length == 2) {
                    String left = parts[0].trim();
                    for (GrammarRule rule : grammarRules) {
                        if (rule.left.equals(left)) {
                            relatedRules.add(rule);
                        }
                    }
                }
            }
            
            // 处理相关的产生式
            for (GrammarRule rule : relatedRules) {
                analysisProcessTextArea.append("  处理产生式: " + rule.left + " -> " + rule.right + "\n");
                
                // 更新First集
                updateFirstSetForRule(rule);
                
                // 更新Follow集
                updateFollowSetForRule(rule);
            }
            
            // 更新显示
            displayFirstSet();
            displayFollowSet();
            
            // 短暂暂停以显示逐步过程
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            
            // 强制刷新界面
            firstSetTable.repaint();
            followSetTable.repaint();
            pagePanel.repaint();
        }
        
        // 最后构造预测分析表
        constructPredictTable();
        analysisProcessTextArea.append("分布显示完成！\n");
        JOptionPane.showMessageDialog(pagePanel, "分布显示完成！", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 为单个产生式更新First集
    private void updateFirstSetForRule(GrammarRule rule) {
        String left = rule.left;
        String right = rule.right;
        
        Set<String> firstSet = firstSets.get(left);
        
        // 处理右部
        if (right.equals("ε") || right.equals("$") || right.isEmpty()) {
            // 空产生式
            firstSet.add("$");
        } else if (!right.isEmpty()) {
            // 计算右部符号串的First集
            boolean canDeriveEpsilon = true;
            char[] symbols = right.toCharArray();
            
            for (char c : symbols) {
                String symbol = String.valueOf(c);
                Set<String> symbolFirstSet = firstSets.get(symbol);
                if (symbolFirstSet != null) {
                    // 添加除$外的所有符号
                    firstSet.addAll(symbolFirstSet.stream()
                            .filter(s -> !s.equals("$"))
                            .collect(Collectors.toSet()));
                    
                    // 如果当前符号不能推导出$，则后续符号不需要考虑
                    if (!symbolFirstSet.contains("$")) {
                        canDeriveEpsilon = false;
                        break;
                    }
                } else {
                    // 如果找不到符号的First集
                    canDeriveEpsilon = false;
                    break;
                }
            }
            
            // 如果所有符号都能推导出$，则整个右部能推导出$
            if (canDeriveEpsilon) {
                firstSet.add("$");
            }
        }
    }
    
    // 为单个产生式更新Follow集
    private void updateFollowSetForRule(GrammarRule rule) {
        String right = rule.right;
        
        if (!right.equals("ε") && !right.equals("$") && !right.isEmpty()) {
            char[] rightSymbols = right.toCharArray();
            
            // 遍历右部的每个符号
            for (int i = 0; i < rightSymbols.length; i++) {
                String symbol = String.valueOf(rightSymbols[i]);
                
                // 只处理非终结符
                if (nonTerminals.contains(symbol)) {
                    Set<String> followSet = followSets.get(symbol);
                    
                    if (i == rightSymbols.length - 1) {
                        // 如果是右部最后一个符号，添加左部的Follow集
                        Set<String> leftFollowSet = followSets.get(rule.left);
                        if (leftFollowSet != null) {
                            followSet.addAll(leftFollowSet);
                        }
                    } else {
                        // 不是最后一个符号
                        // 计算后面符号串的First集
                        boolean canDeriveEpsilon = true;
                        
                        // 处理后续每个符号
                        for (int j = i + 1; j < rightSymbols.length; j++) {
                            String nextSymbol = String.valueOf(rightSymbols[j]);
                            Set<String> nextFirstSet = firstSets.get(nextSymbol);
                            
                            if (nextFirstSet != null) {
                                // 添加除$外的所有符号
                                followSet.addAll(nextFirstSet.stream()
                                        .filter(s -> !s.equals("$"))
                                        .collect(Collectors.toSet()));
                                
                                // 如果当前符号不能推导出$，则后续符号不需要考虑
                                if (!nextFirstSet.contains("$")) {
                                    canDeriveEpsilon = false;
                                    break;
                                }
                            } else {
                                canDeriveEpsilon = false;
                                break;
                            }
                        }
                        
                        // 如果后续所有符号都能推导出$，则添加左部的Follow集
                        if (canDeriveEpsilon) {
                            Set<String> leftFollowSet = followSets.get(rule.left);
                            if (leftFollowSet != null) {
                                followSet.addAll(leftFollowSet);
                            }
                        }
                    }
                }
            }
        }
    }
    
    // 执行分析
    private void performAnalysis() {
        if (predictTable.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请先构造预测分析表！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        String input = inputWordTextArea.getText().trim();
        if (input.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "请输入单词串！", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        // 执行非递归预测分析
        nonRecursivePredictiveAnalysis(input);
    }
    
    // 非递归预测分析
    private void nonRecursivePredictiveAnalysis(String input) {
        // 初始化分析栈
        Stack<String> stack = new Stack<>();
        stack.push("$"); // 结束符
        
        // 获取开始符号（第一个输入的非终结符）
        if (grammarRules.isEmpty() || orderedNonTerminals.isEmpty()) {
            JOptionPane.showMessageDialog(pagePanel, "文法为空！", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        String startSymbol = orderedNonTerminals.get(0);
        stack.push(startSymbol);
        
        // 处理输入串，添加结束符
        String[] inputSymbols = (input + " $").split("\\s+");
        int inputIndex = 0;
        
        // 分析过程记录
        StringBuilder process = new StringBuilder();
        process.append("非递归预测分析过程:\n");
        process.append(String.format("%-20s %-30s %-30s %-20s\n", "栈", "输入", "动作", "说明"));
        process.append("------------------------------------------------------------------------------------------------------------------------\n");
        
        while (!stack.isEmpty()) {
            String topSymbol = stack.peek();
            String currentInput = inputSymbols[inputIndex];
            
            process.append(String.format("%-20s %-30s", 
                stackToString(stack), 
                String.join(" ", Arrays.copyOfRange(inputSymbols, inputIndex, inputSymbols.length))));
            
            if (topSymbol.equals(currentInput)) {
                // 匹配终结符
                if (topSymbol.equals("$")) {
                    // 分析成功
                    process.append(String.format(" %-30s %-20s\n", "匹配$", "接受"));
                    break;
                } else {
                    // 弹出匹配的符号
                    stack.pop();
                    inputIndex++;
                    process.append(String.format(" %-30s %-20s\n", "匹配" + topSymbol, "弹出并前进"));
                }
            } else if (nonTerminals.contains(topSymbol)) {
                // 栈顶是非终结符，查找预测分析表
                Map<String, String> tableRow = predictTable.get(topSymbol);
                if (tableRow != null) {
                    String production = tableRow.get(currentInput);
                    if (production != null) {
                        // 弹出栈顶
                        stack.pop();
                        
                        // 获取产生式右部
                        String[] parts = production.split("->");
                        if (parts.length == 2) {
                            String right = parts[1].trim();
                            process.append(String.format(" %-30s %-20s\n", "输出" + production, "使用产生式"));
                            
                            // 将右部符号逆序压入栈
                            if (!right.equals("ε") && !right.equals("$") && !right.isEmpty()) {
                                char[] rightSymbols = right.toCharArray();
                                for (int i = rightSymbols.length - 1; i >= 0; i--) {
                                    String symbol = String.valueOf(rightSymbols[i]);
                                    stack.push(symbol);
                                }
                            }
                        }
                    } else {
                        // 表项为空，出错
                        process.append(String.format(" %-30s %-20s\n", "查表失败", "错误"));
                        process.append("\n分析失败：在预测分析表中找不到对应的产生式\n");
                        analysisProcessTextArea.setText(process.toString());
                        return;
                    }
                } else {
                    // 没有对应的表行，出错
                    process.append(String.format(" %-30s %-20s\n", "查表失败", "错误"));
                    process.append("\n分析失败：非终结符在预测分析表中无对应行\n");
                    analysisProcessTextArea.setText(process.toString());
                    return;
                }
            } else {
                // 栈顶是终结符但不匹配，出错
                process.append(String.format(" %-30s %-20s\n", "不匹配", "错误"));
                process.append("\n分析失败：栈顶终结符与输入符号不匹配\n");
                analysisProcessTextArea.setText(process.toString());
                return;
            }
        }
        
        process.append("\n分析成功完成！\n");
        analysisProcessTextArea.setText(process.toString());
        JOptionPane.showMessageDialog(pagePanel, "分析完成，详情请查看分析过程区域！", "提示", JOptionPane.INFORMATION_MESSAGE);
    }
    
    // 将栈转换为字符串表示
    private String stackToString(Stack<String> stack) {
        StringBuilder sb = new StringBuilder();
        for (int i = stack.size() - 1; i >= 0; i--) {
            sb.append(stack.get(i));
            if (i > 0) sb.append(" ");
        }
        return sb.toString();
    }
    
    // 保存结果
    private void saveResult() {
        int result = fileChooser.showSaveDialog(pagePanel);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            try (PrintWriter writer = new PrintWriter(new FileWriter(file))) {
                writer.println("文法:");
                writer.println(grammarTextArea.getText());
                writer.println();
                
                writer.println("First集:");
                for (int i = 0; i < firstSetTable.getRowCount(); i++) {
                    for (int j = 0; j < firstSetTable.getColumnCount(); j++) {
                        writer.print(firstSetTable.getValueAt(i, j));
                        if (j < firstSetTable.getColumnCount() - 1) {
                            writer.print("\t");
                        }
                    }
                    writer.println();
                }
                writer.println();
                
                writer.println("Follow集:");
                for (int i = 0; i < followSetTable.getRowCount(); i++) {
                    for (int j = 0; j < followSetTable.getColumnCount(); j++) {
                        writer.print(followSetTable.getValueAt(i, j));
                        if (j < followSetTable.getColumnCount() - 1) {
                            writer.print("\t");
                        }
                    }
                    writer.println();
                }
                writer.println();
                
                writer.println("预测分析表:");
                for (int i = 0; i < predictTableDisplay.getRowCount(); i++) {
                    for (int j = 0; j < predictTableDisplay.getColumnCount(); j++) {
                        writer.print(predictTableDisplay.getValueAt(i, j));
                        if (j < predictTableDisplay.getColumnCount() - 1) {
                            writer.print("\t");
                        }
                    }
                    writer.println();
                }
                writer.println();
                
                writer.println("分析过程:");
                writer.println(analysisProcessTextArea.getText());
                
                JOptionPane.showMessageDialog(pagePanel, "结果保存成功！", "提示", JOptionPane.INFORMATION_MESSAGE);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(pagePanel, "文件保存错误: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    
    // 文法产生式类
    static class GrammarRule {
        String left;
        String right;
        
        GrammarRule(String left, String right) {
            this.left = left;
            this.right = right;
        }
    }
    
    public JPanel SwitchLookingAnalysis() {
        return pagePanel;
    }
    
    public JMenuBar GetLookingAnalysisMenuBar() {
        return menuBar;
    }
}